using System;
using MbUnit.Framework;
using DotNetNukeMVPWizard.ProjectConfiguration;
using System.Collections.Generic;
using Microsoft.VisualStudio.TemplateWizard;
using Moq;
using System.Windows.Forms;


namespace DotNetNukeMVPWizard.Tests
{
    [TestFixture]
    public class TestIWizardImplementation
    {
        #region Properties
        private Dictionary<string, string> ReplacementsDictionary;
        private const string STR_KEY_ProjectName = "$projectname$";
        private const string STR_YourCompany = "Your Company";
        private const string STR_Safe_Your_Company = "Your_Company";
        private const string STR_ProjectNamespaceName = STR_Safe_Your_Company + ".Modules";
        private const string STR_KEY_SafeProjectName = "$safeprojectname$";
        private const string STR_VALUE_ProjectName = "Sample Project";
        private const string STR_VALUE_SafeProjectName = "Sample_Project";
        private IWizardImplementation Actual;

        private Mock<IConfigurationForm> MockForm;
        private Mock<IMvpMultiProjectConfiguration> MockConfigurations;
        #endregion

        #region SetUp
        [SetUp]
        public void SetUp()
        {
            // Setup basics of ReplacementsDictionary
            ReplacementsDictionary = new Dictionary<string, string>();
            ReplacementsDictionary.Add(STR_KEY_ProjectName, STR_VALUE_ProjectName);
            ReplacementsDictionary.Add(STR_KEY_SafeProjectName, STR_VALUE_SafeProjectName);

            // Setup Mocks
            MockForm = new Mock<IConfigurationForm>();
            MockConfigurations = new Mock<IMvpMultiProjectConfiguration>();

            // Setup Common Expectations
            MockForm.Setup(self => self.ShowDialog()).Returns(DialogResult.OK);
            MockForm.SetupSet(self => self.Configuration = MockConfigurations.Object);
            MockConfigurations.Setup(self => self.IsValid).Returns(true);
            MockConfigurations.Setup(self => self.FillDictionary(ReplacementsDictionary));
            MockConfigurations.Setup(self => self.SetParentProjectName(STR_VALUE_SafeProjectName));
            MockConfigurations.Setup(self => self.SetYourCompany(STR_YourCompany));
            MockConfigurations.Setup(self => self.SetProjectNamespaceName(STR_ProjectNamespaceName));

            Actual = new IWizardImplementation(MockForm.Object, MockConfigurations.Object);
        }
        #endregion

        #region IConfiguartionForm Expectations
        [Test]
        [Description("")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Throw_WizardCancellationException_When_Form_Cancels()
        {
            MockForm.Setup(self => self.ShowDialog()).Returns(DialogResult.Cancel);
            Assert.Throws<WizardCancelledException>(() => { Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsMultiProject, null); });
        }

        [Test]
        [Description("")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Not_Pass_Configuration_To_Form_When_WizardRunKind_AsNewProject()
        {
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsNewProject, null);

            MockForm.VerifySet(self => self.Configuration = It.IsAny<IMvpMultiProjectConfiguration>(), Times.Never());
        }

        [Test]
        [Description("")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Launch_Form_When_WizardRunKind_AsMultiProject()
        {
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsMultiProject, null);

            MockForm.Verify(self => self.ShowDialog());
        }

        [Test]
        [Description("")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Pass_Configuration_To_Form_When_WizardRunKind_AsMultiProject()
        {
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsMultiProject, null);

            MockForm.VerifySet(self => self.Configuration = MockConfigurations.Object);
        }

        [Test]
        [Description("")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Not_Launch_Form_When_WizardRunKind_AsNewProject()
        {
            MockForm = new Mock<IConfigurationForm>();
            Actual = new IWizardImplementation(MockForm.Object, MockConfigurations.Object);

            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsNewProject, null);

            MockForm.VerifyAll();
        }

        #endregion

        #region IMvpMultiProjectConfiguration Expectations
        #region WizardRunKind.AsMultiProject
        [Test]
        [Description("Ensure that the IWizardImplementation copies the ProjectName to the ParentProjectName on WizardRunKind.AsMultiProject")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Set_ParentProjectName_When_WizardRunKind_AsMultiProject()
        {
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsMultiProject, null);
            MockConfigurations.Verify(self => self.SetParentProjectName(STR_VALUE_ProjectName), Times.Once());
        }

        [Test]
        [Description("Ensure that the IWizardImplementation sets the YourCompany to a default of \"Your Company\" on WizardRunKind.AsMultiProject")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Set_YourCompany_When_WizardRunKind_AsMultiProject()
        {
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsMultiProject, null);
            MockConfigurations.Verify(self => self.SetYourCompany(STR_YourCompany), Times.Once());
        }

        [Test]
        [Description("Ensure that the IWizardImplementation sets the ProjectNamespaceName to a default of \"Your_Company.Modules\" on WizardRunKind.AsMultiProject")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Set_ProjectNamespaceName_When_WizardRunKind_AsMultiProject()
        {
            MockConfigurations.SetupGet(self => self.SafeYourCompany).Returns(STR_Safe_Your_Company);
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsMultiProject, null);
            MockConfigurations.Verify(self => self.SetProjectNamespaceName(STR_ProjectNamespaceName), Times.Once());
        }

        [Test]
        [Description("Ensure that the IWizardImplementation checks IsValid on its MVPMultipProjectConfiguration instance on WizardRunKind.AsMultiProject.")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Validate_Custom_Configurations()
        {
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsMultiProject, null);

            MockConfigurations.Verify(self => self.IsValid);
        }
        #endregion

        #region WizardRunKind.AsNewProject
        [Test]
        [Description("Ensure that the IWizardImplementation copies the ProjectName to the ParentProjectName and SafeParentProjectName on WizardRunKind.AsNewProject")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Not_Set_ParentProjectName_When_WizardRunKind_AsNewProject()
        {
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsNewProject, null);
            MockConfigurations.Verify(self => self.SetParentProjectName(STR_VALUE_ProjectName), Times.Never());
        }

        [Test]
        [Description("Ensure that the IWizardImplementation preserves the ParentProjectName and SafeParentProjectName on WizardRunKind.AsNewProject")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Not_ReSet_ParentProjectName_When_WizardRunKind_AsNewProject()
        {
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsMultiProject, null);
            Actual = new IWizardImplementation();
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsNewProject, null);
            MockConfigurations.Verify(self => self.SetParentProjectName(STR_VALUE_ProjectName), Times.Once());
        }


        [Test]
        [Description("Ensure that the IWizardImplementation re-applies the MvpMultiProjectConfiguration placeholder values to the ReplacementsDictionary when run as WizardRunKind.AsNewProject.")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Fill_ReplacementsDictionary_With_MvpMultiProjectConfiguration_Values_When_WizardRunKind_AsNewProject()
        {
            Actual.RunStarted(null, ReplacementsDictionary, WizardRunKind.AsNewProject, null);
            MockConfigurations.Verify(self => self.FillDictionary(ReplacementsDictionary), Times.Once());
        }
        #endregion
        #endregion

        #region Administrator Permission Expectations
        [Ignore("Implement this behaviour at a later date")]
        [Test]
        [Description("Ensure that the IWizardImplementation checks for an elevated administrator access in running the Visual Studio template")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Abort_If_Not_Running_Elevated_Permissions()
        {
            // NOTE: Need a pre-condition Assert that this test can only be "validated" if VS is currently running under elevatd priviledges
            //      IDEA: Check the permissions - if not running as Administrator, then do an   Assert.Inconclusive()

            // TODO: Expand this to be two tests, where one is always "inconclusive", or (better yet), ignored
            Assert.Fail("Not Yet Implemented."); // TEST: Implement this soon.
        }
        #endregion

        #region (Unused/incomplete expectations)
        [Ignore]
        [Test]
        [Description("")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Generate_ReplacementsDictionary_With_Custom_Configurations()
        {
            Assert.Fail("Not Yet Implemented."); // TEST: Implement this soon.
        }

        [Ignore]
        [Test]
        [Description("")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void IWizardImplementation_Should_Preserve_ReplacementsDictionary_Custom_Configurations_Whe_WizardRunKind_AsNewProject()
        {
            Assert.Fail("Not Yet Implemented."); // TEST: Implement this soon.
        }
        #endregion
    }
}
